package com.caijg.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.dashscope.app.Application;
import com.alibaba.dashscope.app.ApplicationParam;
import com.alibaba.dashscope.app.ApplicationResult;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caijg.domain.dto.EvaluationDTO;
import com.caijg.domain.dto.TongueDescriptionDTO;
import com.caijg.domain.po.EvaluationResult;
import com.caijg.domain.po.TongueDiagnosis;
import com.caijg.domain.vo.Result;
import com.caijg.exception.CustomException;
import com.caijg.mapper.EvaluationResultMapper;
import com.caijg.service.IEvaluationResultService;
import com.caijg.service.IPromptService;
import com.caijg.service.ITongueDiagnosisService;
import com.caijg.utils.UserContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.caijg.utils.Constant.*;

/**
 * <p>
 * 评测结果表 服务实现类
 * </p>
 *
 * @author caijg
 * @since 2024-12-28
 */
@Service
@Slf4j
public class EvaluationResultServiceImpl extends ServiceImpl<EvaluationResultMapper, EvaluationResult> implements IEvaluationResultService {

    @Autowired
    private IPromptService promptService;
    @Autowired
    private ITongueDiagnosisService tongueDiagnosisService;

    // 体质评估假数据
//    @Override
//    public Result getResult(EvaluationDTO evaluationDTO) throws Exception {
//        Thread.sleep(4000);
//        String s = "{" +
//                "  'tongueCoatingAnalysis': '1',\n" +
//                "  'healthAnalysis': '18',\n" +
//                "  'regulationPlan': '75',\n" +
//                "  'proneDiseases': '1',\n" +
//                "  'createTime': '2024-10-1',\n" +
//                "  'id': '3',\n" +
//                "  'tongueDiagnosisId': '37'" +
//                "}";
//        JSON jsonResult = JSONUtil.parse(s);
//
//        return Result.success(jsonResult);
//    }

    /**
     * 获取体质体质评估的返回结果
     */
    @Override
    @Transactional
    public Result getResult(EvaluationDTO evaluationDTO) throws Exception {

        // 1.拿到用户的问卷
        JSONObject jsonObject = new JSONObject();

        // 拿到舌苔的五个特征描述
        TongueDiagnosis tongueDiagnosis = tongueDiagnosisService.getById(evaluationDTO.getTongueDiagnosisId());
        TongueDescriptionDTO tongueDescriptionDTO = BeanUtil.toBean(tongueDiagnosis, TongueDescriptionDTO.class);
        // 拿到问诊的一系列问卷
        jsonObject.set("问诊：", evaluationDTO.getAnswers());
        jsonObject.set("舌诊：", tongueDescriptionDTO);

        // 2.发送给Qwen大模型进行分析，拿到JSON
        String llModelResult = getLLModelResult(jsonObject.toString());
        log.info("评测结果:{}", llModelResult);

        // 3.防止大模型回复的不是纯JSON，做一个容错处理
        int begin = llModelResult.indexOf("{");
        int end = llModelResult.lastIndexOf("}");
        // 如果完全就没有JSON格式，则抛出异常
        if (begin == -1 || end == -1) {
            throw new CustomException("内部错误，请重试！", 500);
        }
        llModelResult = llModelResult.substring(begin, end + 1);

        // 4.解析诊断结果为JSON格式
        JSON jsonResult = JSONUtil.parse(llModelResult);

        // 5.存储报告到数据库
        // 5.1 从JSON中把数据取出来，创建一个对象
        EvaluationResult evaluationResult = EvaluationResult.builder()
                .userId(UserContext.getUid())
                .tongueCoatingAnalysis(jsonResult.getByPath("tongueCoatingAnalysis", String.class))
                .healthAnalysis(jsonResult.getByPath("healthAnalysis", String.class))
                .regulationPlan(jsonResult.getByPath("regulationPlan", String.class))
                .proneDiseases(jsonResult.getByPath("proneDiseases", String.class))
                .tongueDiagnosisId(tongueDiagnosis.getId())
                .createTime(LocalDateTime.now())
                .build();
        // 5.2保存到数据库
        this.save(evaluationResult);

        // 6.给返回结果加一个createTime、id
        jsonResult.putByPath("createTime", evaluationResult.getCreateTime());
        jsonResult.putByPath("id", evaluationResult.getId());
        jsonResult.putByPath("tongueDiagnosisId", tongueDiagnosis.getId());

        // 7.返回结果
        return Result.success(jsonResult);
    }

    /**
     * 获取大模型返回的体质评估的结果
     * @param userInfo 用户作答的问卷
     */
    private String getLLModelResult(String userInfo) throws NoApiKeyException, InputRequiredException {
        // 1.设置大模型调用参数
        ApplicationParam param = ApplicationParam.builder()
                .apiKey(API_KEY)
                .appId(APP_ID)
                // 设置提示词
                .prompt(promptService.getPromptByName(EVALUATION_PROMPT_NAME) + userInfo)
                .build();

        Application application = new Application();
        // 2.调用Qwen大模型，拿到结果
        ApplicationResult result = application.call(param);

        // 3.返回结果
        return result.getOutput().getText();
    }

    /**
     * 获取历史评估记录
     */
    @Override
    public Result getHistory() {
        // 1.获取当前用户id
        Long userId = UserContext.getUid();

        // 2.查询数据库，获取当前用户的历史评测结果
        List<EvaluationResult> list = this.query()
                .eq("user_id", userId)
                .orderByDesc("create_time")
                .list();
        return Result.success(list);
    }

    /**
     * 删除体质评估历史记录
     * @param ids 需要删除的历史评测结果的id
     */
    @Override
    public Result deleteHistory(ArrayList<String> ids) {
        // 1.删除
        boolean ok = this.removeByIds(ids);

        // 2.返回结果
        return Result.success(ok);
    }
}